﻿define([
    'Xjs/core/util'
],
function (util) {
    'use strict';

    // Builds the html from the component
    var Node = function (tag) {

        this.tag = tag; // The name of the html tag
        this.attributes = {}; // The html attributes
        this.theme = 'base';
        this.children = []; // The children builders

        // The function that prepends the theme to the class
        this.themeClassNameProvider = function (cls) {
            return this.theme + '-' + cls;
        };
    };

    Node.prototype =
    {
        // Adds attributes if they do not have a key in the builder, otherwise replaces them
        addAttributes: function (attributes) {

            for (var key in attributes) {

                var attribute = attributes[key];

                if (key == 'cls') {

                    key = 'class';

                    //                    // Break the classes, prepend the theme and re-assemble them again
                    //                    var classes = [];

                    //                    attribute.split(' ').forEach(function (cls) {
                    //                        classes.push(this.themeClassNameProvider(cls));
                    //                    },
                    //                    this);

                    //                    attribute = classes.join(' ');
                }
                else if (key == 'style') {
                    attribute = util.styleToString(attribute);
                }

                this.attributes[key] = attribute;
            }

            return this;
        },

        addClass: function (cls) {
            if (!this.attributes['class']) {
                this.attributes['class'] = cls;
            }
            else {
                var c = this.attributes['class'] + ' ' + cls;
                this.attributes['class'] = c;
            }
        },
        // Replaces class p by n or appends it if p is not found
        replaceClass: function (p, n) {
            if (!this.attributes['class']) {
                this.attributes['class'] = n;
            }
            else {
                var a = this.attributes['class'].split(' '),
                c = '';

                a.forEach(function (cl) {
                    if (cl != p) {
                        c += cl + ' ';
                    }
                });

                c += n;

                this.attributes['class'] = c;
            }
        },

        // Adds a child builder node
        addNode: function (n) {
            this.children.push(n);

            return this;
        },

        clear: function () {
            this.children.length = 0;
        },

        // Adds a text node to this builder
        addText: function (text) {
            this.children.push(new Text(text));

            return this;
        },

        // Adds a text node or replaces its text if already exists
        setText: function (text) {
            if (this.children && this.children.length > 0) {
                this.children[0].text = text;
            }
            else {
                this.addText(text);
            }
        },

        getText: function () {
            if (this.children && this.children.length > 0) {
                return this.children[0].text;
            }

            return '';
        },

        setTheme: function (theme) {

            this.theme = theme || this.theme;

            return this;
        },

        // Renders the node returning a string with the html markup
        render: function () {
            var html = '<' + this.tag + ' '; // String concatenation is faster in modern browsers

            for (var key in this.attributes) {
                var attribute = this.attributes[key];

                if (util.isDefined(attribute)) {
                    html += key + '="' + attribute + '" ';
                }
            };

            if (this.isSelfClosing() && this.children.length == 0) {
                html += '/>';
            }
            else {
                html += '>';
                html += this.renderChildren();
                html += '</' + this.tag + '>';
            }

            return html;
        },

        // Renders the child node builders
        renderChildren: function () {
            var html = '';

            this.children.forEach(function (builder) {
                html += builder.render();
            }, this);

            return html;
        },

        // Tests whether the tag is self closing
        isSelfClosing: function () {
            return !this.nonSelfClosing[this.tag];
        },

        // The hash with non self closing tags
        nonSelfClosing:
        {
            span: true, // Required by latest browsers
            div: true, // Required by latest browsers
            textarea: true,
            script: true,
            em: true,
            strong: true,
            option: true,
            select: true
        }
    };

    var Text = function (text) {
        this.text = text;
    };

    Text.prototype =
    {
        render: function () {
            return this.text || '';
        }
    };

    return {
        // Creates a new html node
        createNode: function (tag) {
            return new Node(tag);
        },

        // Creates a new text element
        createText: function (text) {
            return new Text(text);
        }
    };

});